﻿using System;
using System.Web.Mvc;
using NHibernate;
using Mailer.Model;
using Mailer.Model.Types;
using System.Net.Mail;
using Mailer.Utilities;
using log4net;

namespace Mailer.Controllers
{
	[HandleError]
	public class MailController : Controller
	{
		[Authorize]
		public ActionResult View(Guid id)
		{
			// TODO: kolla access
			 
			var sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				var mail = sess.Get<Mail>(id);
				if (mail != null)
				{
					var app = sess.Get<Application>(mail.ApplicationID);

					//	RouteTable.Routes.GetVirtualPath( 

					ViewData["ID"] = mail.ID;
					ViewData["Name"] = mail.Name;

					ViewData["Mail"] = mail;

					ViewData["ApplicationID"] = mail.ApplicationID;

					ViewData["AllLists"] = app.Lists;
					ViewData["Lists"] = mail.Lists;

					// ViewData["NumRecipients"] = 0;

					/*	
				 	ViewData["Recipients"] = sess.CreateQuery("select r from Mail as m inner join m.Lists as l inner join l.Recipients as r where m.ID = :mail")
						.SetParameter("mail", mail.ID)
						.List<Recipient>();
					*/

					ViewData["NumRecipients"] = (long)sess.CreateQuery("select r.ID as n from Mail as m inner join m.Lists as l inner join l.Recipients as r where m.ID = :mail group by r.ID")
						.SetParameter("mail", mail.ID)
						.List().Count;

					/*	ViewData["NumRecipients"] = (long)sess.CreateQuery("select count(distinct r.ID) as n from Mail as m inner join m.Lists as l inner join l.Recipients as r where m.ID = :mail")
							.SetParameter("mail", mail.ID)
							.UniqueResult();
						*/
					/*
					Recipient recip = sess.CreateQuery("select r from Recipient as r where r.ApplicationID = :app and r.Email = :mail")
						.SetParameter("app", mail.ApplicationID)
						.SetParameter("mail", mail.ID)
						.UniqueResult<Recipient>();

					if (recip != null)
					{
						ViewData["HtmlPreviewURL"] = Configuration.RootURL + "public/m/" + recip.ID + "/" + mail.ID + "/html";
						ViewData["PlaintextPreviewURL"] = Configuration.RootURL + "public/m/" + recip.ID + "/" + mail.ID + "/text";
					}
					else*/
					{
						ViewData["HtmlPreviewURL"] = Configuration.RootURL + "public/m/" + mail.ID + "/html";
						ViewData["PlaintextPreviewURL"] = Configuration.RootURL + "public/m/" + mail.ID + "/text";
					}

					if (ViewData["email"] == null)
						ViewData["email"] = mail.GetPropertyValue("senderemail");
				}
				SessionUtilities.EndSession(sess);
			}
			return base.View();
		}


		[Authorize]
		public ActionResult StartSend(Guid id)
		{
			ActionResult ret = null;

			var sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				var mail = sess.Get<Mail>(id);
				if (mail != null)
				{
					var app = sess.Get<Application>(mail.ApplicationID);

					using (ITransaction transaction = sess.BeginTransaction())
					{
						sess.CreateQuery("delete from SendQueue as sq where sq.MailID = :mail")
							.SetParameter("mail", mail.ID)
							.ExecuteUpdate();

						transaction.Commit();
					}

					long queued = 0;

					var recips = sess.CreateQuery("select distinct r from Mail as m inner join m.Lists as l inner join l.Recipients as r where m.ID = :mail")
						.SetParameter("mail", mail.ID)
						.List<Recipient>();

					using (var transaction = sess.BeginTransaction())
					{
						foreach (var r in recips)
						{
							var sq = new SendQueue();
							sq.MailID = mail.ID;
							sq.RecipientID = r.ID;
							sq.QueuedDate = DateTime.Now;
							sq.QueuedBy = Utilities.GetUserID(this);
							sq.State = (int)QueueState.NotSent;
							sq.Priority = 10;
							sess.Save(sq);

							queued++;
						}

						mail.State = (int)MailState.Sending;
						sess.Save(mail);

						transaction.Commit();
					}

					TempData["message"] = "The mail \"" + mail.Name + "\" was queued to " + queued + " recipients.\n";

					var appusers = sess.CreateQuery("select u from User u inner join u.Applications a where a.ID = :app")
						.SetParameter("app", app.ID)
						.List<User>();
					foreach (var u in appusers)
					{
						MailUtilities.QueueStatusMessage(new MailAddress(u.Email, u.Username),
							"Mail queued: \"" + mail.Name + "\"",
							"Your mail \"" + mail.Name + "\" has been queued for sending to " + queued + " recipients\n\n" +
							"You will receive another mail after the mail has been sent.\n\n" +
							"You can go to this page to view the progress: " + Configuration.RootURL + "applications/View/" + mail.ApplicationID + "\n\n" +
							"Or go to this page to view all your applications: " + Configuration.RootURL);
					}

					ret = RedirectToAction("View", "Application", new { id = app.ID });
				}
				SessionUtilities.EndSession(sess);
			}

			return ret;
		}


		[Authorize]
		public ActionResult SendPreview(Guid id, string email)
		{
			// TODO: kolla access
			var logger = log4net.LogManager.GetLogger(typeof(MailController));

			var sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				var mail = sess.Get<Mail>(id);
				if (mail != null)
				{
					var app = sess.Get<Application>(mail.ApplicationID);

					var recip = sess.CreateQuery("select r from Recipient as r where r.ApplicationID = :app and r.Email = :mail")
						.SetParameter("app", mail.ApplicationID)
						.SetParameter("mail", email)
						.UniqueResult<Recipient>();

					//	string subj = mail.GetPropertyValue("subject"); ;


					MailMessage msg = null;

					bool ok = false;
					try
					{
						if (recip != null)
						{
							msg = mail.PrepareMail(recip);
						//	msg.To.Add(app.GetToAddress());
						//	msg.Bcc.Add(new MailAddress(email));
						}
						else
						{
							msg = mail.PrepareMail((Recipient)null);
							msg.To.Add(app.GetToAddress());
							msg.Bcc.Add(new MailAddress(email));
						}
						
						logger.Debug("from: " + msg.From.ToString());

						foreach (var adr in msg.To)
							logger.Debug("to: " + adr.ToString());

						foreach (var adr in msg.Bcc)
							logger.Debug("bcc: " + adr.ToString());

						logger.Debug("replyto: " + msg.ReplyTo.ToString());

						logger.Debug("subject: " + msg.Subject);

						foreach (string key in msg.Headers)
							logger.Debug("header[" + key + "]: " + msg.Headers[key].ToString());

						logger.Debug("sending...");
					}
					catch (Exception zz)
					{
						log4net.LogManager.GetLogger(typeof(MailController)).Error(zz);
						if (zz.InnerException != null) {
							log4net.LogManager.GetLogger(typeof(MailController)).Error(zz.InnerException);
							if (zz.InnerException.InnerException != null)
								log4net.LogManager.GetLogger(typeof(MailController)).Error(zz.InnerException.InnerException);
						}
					}

					if (msg != null)
					{
						try
						{
							var sc = new SmtpClient();
							sc.Send(msg);
							ok = true;
						}
						catch (SmtpException szz)
						{
							log4net.LogManager.GetLogger(typeof(MailController)).Error(szz);
							log4net.LogManager.GetLogger(typeof(MailController)).Error(szz.StatusCode);
							log4net.LogManager.GetLogger(typeof(MailController)).Error(szz.Message);
							if (szz.InnerException != null)
							{
								log4net.LogManager.GetLogger(typeof(MailController)).Error(szz.InnerException);
							}
						}
						catch (Exception zz)
						{
							log4net.LogManager.GetLogger(typeof(MailController)).Error(zz);
							if (zz.InnerException != null)
							{
								log4net.LogManager.GetLogger(typeof(MailController)).Error(zz.InnerException);
								if (zz.InnerException.InnerException != null)
									log4net.LogManager.GetLogger(typeof(MailController)).Error(zz.InnerException.InnerException);
							}
						}
					}

					if (ok)
						TempData.Add("message", "Mail \""+msg.Subject+"\" sent to \"" + email + "\".");
					else
						TempData.Add("message", "Failed to send mail to \"" + email + "\".");
				}
				SessionUtilities.EndSession(sess);
			}

			return RedirectToAction("View", "Mail", new { id = id });
		}





		[Authorize]
		[AcceptVerbs(HttpVerbs.Get)]
		public ActionResult New()
		{
			var appid = new Guid(Request["application"]);

			ViewData["ApplicationID"] = appid;

			// Mail mail = SessionUtilities.CurrentSession.Get<Mail>(id);

			// ViewData["ID"] = mail.ID;
			// ViewData["Name"] = mail.Name;

			var sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				var app = sess.Get<Application>(appid);

				ViewData["Lists"] = app.Lists;
				SessionUtilities.EndSession(sess);
			}

			return base.View();
		}

		[Authorize]
		[AcceptVerbs(HttpVerbs.Post)]
		public ActionResult New(string name, Guid[] lists, string importhtml, string importplaintext)
		{
			ActionResult res = null;

			var userid = Utilities.GetUserID(this);

			if (name.Length < 5)
			{
				ModelState.AddModelError("_FORM", "Name should be 5 characters or more.");
			}
			else
			{

				var sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					var appid = new Guid(Request["application"]);

					using (ITransaction transaction = sess.BeginTransaction())
					{
						var app = sess.Get<Application>(appid);

						var newmail = new Mail();
						newmail.Name = name;
						newmail.CreatedBy = userid;
						newmail.UpdatedBy = userid;
						newmail.CreatedDate = DateTime.Now;
						newmail.UpdatedDate = DateTime.Now;
						newmail.ApplicationID = appid;
						newmail.State = (int)MailState.NotSent;

						if (lists != null)
						{
							foreach (Guid lid in lists)
							{
								List list = sess.Get<List>(lid);
								newmail.Lists.Add(list);
							}
						}

						sess.Save(newmail);

						newmail.SetPropertyValue(sess, "subject", name);

						newmail.SetPropertyValue(sess, "sendername", app.GetPropertyValue("sendername"));
						newmail.SetPropertyValue(sess, "senderemail", app.GetPropertyValue("senderemail"));
						newmail.SetPropertyValue(sess, "recipientname", app.GetPropertyValue("recipientname"));
						newmail.SetPropertyValue(sess, "recipientemail", app.GetPropertyValue("recipientemail"));
						newmail.SetPropertyValue(sess, "replytoemail", app.GetPropertyValue("replytoemail"));

						if (!string.IsNullOrEmpty(importhtml))
						{
							newmail.SetPropertyValue(sess, "htmlurl", importhtml);
							newmail.SetPropertyValue(sess, "htmlbody", Ripper.TryRip(importhtml));
						}

						if (!string.IsNullOrEmpty(importplaintext))
						{
							newmail.SetPropertyValue(sess, "plaintexturl", importplaintext);
							newmail.SetPropertyValue(sess, "plaintextbody", Ripper.TryRip(importplaintext));
						}

						app.Mails.Add(newmail);

						sess.Save(app);

						res = RedirectToAction("Edit", "Mail", new { ID = newmail.ID });
						transaction.Commit();
					}
					SessionUtilities.EndSession(sess);
				}
			}

			// If we got this far, something failed, redisplay form
			if (res == null)
				res = New();

			return res;
		}





		[Authorize]
		[AcceptVerbs(HttpVerbs.Get)]
		public ActionResult Edit(Guid id)
		{
			// Mail mail = SessionUtilities.CurrentSession.Get<Mail>(id);

			// ViewData["ID"] = mail.ID;
			// ViewData["Name"] = mail.Name;

			var sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				var mail = sess.Get<Mail>(id);
				var app = sess.Get<Application>(mail.ApplicationID);

				ViewData["ID"] = mail.ID;
				ViewData["ApplicationID"] = mail.ApplicationID;
				ViewData["Name"] = mail.Name;
				ViewData["Lists"] = app.Lists;
				ViewData["SelectedLists"] = mail.Lists;

				ViewData["subject"] = mail.GetPropertyValue("subject");
				ViewData["senderemail"] = mail.GetPropertyValue("senderemail");
				ViewData["sendername"] = mail.GetPropertyValue("sendername");
				ViewData["recipientemail"] = mail.GetPropertyValue("recipientemail");
				ViewData["recipientname"] = mail.GetPropertyValue("recipientname");
				ViewData["replytoemail"] = mail.GetPropertyValue("replytoemail");
				ViewData["plaintextbody"] = mail.GetPropertyValue("plaintextbody");
				ViewData["htmlbody"] = mail.GetPropertyValue("htmlbody");

				ViewData["isarchived"] = (mail.State == (int)MailState.Archived);

				SessionUtilities.EndSession(sess);
			}

			return base.View();
		}

		[Authorize]
		[ValidateInput(false)]
		[AcceptVerbs(HttpVerbs.Post)]
		public ActionResult Edit(
			Guid id,
			string name,
			Guid[] lists,
			string subject,
			string senderemail,
			string sendername,
			string replytoemail,
			string plaintextbody,
			string htmlbody,
			string recipientemail,
			string recipientname,
			 bool isarchived
		)
		{
			ActionResult res = null;

			Guid userid = Utilities.GetUserID(this);

			if (name.Length < 5)
			{
				ModelState.AddModelError("_FORM", "Name should be 5 characters or more.");
			}
			else
			{
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					using (ITransaction transaction = sess.BeginTransaction())
					{
						Mail mail = sess.Get<Mail>(id);
						Application app = sess.Get<Application>(mail.ApplicationID);

						mail.Name = name;
						mail.UpdatedBy = userid;
						mail.Lists.Clear();

						if (isarchived)
						{
							if (mail.State != (int)MailState.Archived)
							{
								mail.State = (int)MailState.Archived;
								mail.UpdatedDate = DateTime.Now;
							}
						}
						else
						{
							if (mail.State == (int)MailState.Archived)
							{
								mail.State = (int)MailState.Sent;
							}

							mail.UpdatedDate = DateTime.Now;
						}

						if (lists != null)
						{
							foreach (Guid lid in lists)
							{
								List list = sess.Get<List>(lid);
								mail.Lists.Add(list);
							}
						}

						sess.Save(mail);

						mail.SetPropertyValue(sess, "subject", subject);
						mail.SetPropertyValue(sess, "senderemail", senderemail);
						mail.SetPropertyValue(sess, "sendername", sendername);
						mail.SetPropertyValue(sess, "recipientemail", recipientemail);
						mail.SetPropertyValue(sess, "recipientname", recipientname);
						mail.SetPropertyValue(sess, "replytoemail", replytoemail);
						mail.SetPropertyValue(sess, "plaintextbody", plaintextbody);
						mail.SetPropertyValue(sess, "htmlbody", htmlbody);

						res = RedirectToAction("View", "Mail", new { ID = id });
						transaction.Commit();
					}
				}
				SessionUtilities.EndSession(sess);
			}

			// If we got this far, something failed, redisplay form
			if (res == null)
				res = Edit(id);

			return res;
		}











	}
}
